﻿using Abp.Application.Services.Dto;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Batman.Cms.Core.Core.SimpleMaintenance.DTO.InputDTO;
using Batman.Core;
using Batman.Maintenance;
using Batman.Maintenance.Enums;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Batman.Cms.Core.Core.SimpleMaintenance.Repositories
{
    public interface IMaintenanceRepository<T> : Abp.Dependency.ITransientDependency where T : Entity<string>
    {
        PagedResultDto<T> Gets(ReadInputDTO input);
    }

    public class MaintenanceRepository<T> where T : Entity<string>
    {
        public IRepository<T, string> repo { get; set; }

        /// <summary>
        /// 查询
        /// </summary>
        /// <returns></returns>
        public PagedResultDto<T> Gets(ReadInputDTO input, MaintenanceModel<T> model)
        {
            var page = input.page;

            var query = repo.GetQuery();

            // 处理连带
            var includes = model.MainTable.GetIncludeList();
            if (includes.Count > 0)
            {
                query = query.Include(includes[0]);
            }

            #region 查询条件

            if (input.filter != null)
            {
                foreach (var item in input.filter)
                {
                    if (item.Val == null) continue;

                    var map = model.SearchBar.PropertyMaps.FirstOrDefault(t => t.FieldName == item.FieldName);
                    if (map == null) continue;

                    var val = (object)item.Val;
                    switch (item.Type)
                    {
                        case MaintenanceFormFieldType.Text:
                            var text = item.Val.ToString();
                            if (string.IsNullOrEmpty(text))
                                break;
                            if (item.Condition == MaintenanceSearchBarCondition.等于)
                            {
                                var textEqualLambda = BuildEqualLambda(item.FieldName, item.Val);
                                query = query.Where(textEqualLambda);
                            }
                            if (item.Condition == MaintenanceSearchBarCondition.包含)
                            {
                                var containsLambda = BuildContainsLambda(item.FieldName, item.Val);
                                query = query.Where(containsLambda);
                            }
                            break;

                        case MaintenanceFormFieldType.Selection:
                            var lambda = BuildEqualLambda(item.FieldName, item.Val);
                            query = query.Where(lambda);
                            break;
                    }

                }
            }

            #endregion

            var total = query.Count();

            #region 排序

            var sort = model.MainTable.GetDefaultSort();
            if (sort.Key != null)
            {
                switch (sort.Value)
                {
                    case OrderBy.Asc:
                        query = query.OrderBy(sort.Key);
                        break;
                    case OrderBy.Desc:
                        query = query.OrderByDescending(sort.Key);
                        break;
                }
            }

            #endregion

            query = query.Skip(page.SkipCount).Take(page.MaxResultCount);
            var items = query.ToList();

            return new PagedResultDto<T>(total, items);
        }

        /// <summary>
        /// 创建Linq Where用的简单表单时
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        Expression<Func<T, bool>> BuildEqualLambda(string fieldName, object val)
        {
            fieldName = Char.ToUpper(fieldName[0]) + fieldName.Substring(1);
            var t = Expression.Parameter(typeof(T), "t");

            var property = Expression.Property(t, fieldName);

            Expression contant = GeneConstantExpression(property, val);

            var equal = Expression.Equal(property, contant);

            var lambda = Expression.Lambda<Func<T, bool>>(equal, t);

            return lambda;
        }

        /// <summary>
        /// 创建Linq Where用的简单表单时
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        Expression<Func<T, bool>> BuildContainsLambda(string fieldName, object val)
        {
            fieldName = Char.ToUpper(fieldName[0]) + fieldName.Substring(1);
            var t = Expression.Parameter(typeof(T), "t");

            var property = Expression.Property(t, fieldName);

            Expression contant = GeneConstantExpression(property, val);

            MethodInfo method = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });

            var contains = Expression.Call(property, method, contant);

            var lambda = Expression.Lambda<Func<T, bool>>(contains, t);

            return lambda;
        }

        /// <summary>
        /// 根据MemberExpression的类型，把值转换成对应的TYPE
        /// </summary>
        /// <param name="property"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        ConstantExpression GeneConstantExpression(MemberExpression property, object val)
        {
            switch (property.Type.ToString())
            {
                case "System.Int32":
                    break;
                case "System.Int64":
                    break;
                case "System.Double":
                    break;
                case "System.DateTime":
                    break;
                case "System.String":
                    return Expression.Constant(val.ToString());
                case "System.Boolean":
                    var valStr = val.ToString();
                    if (new string[] { "0", "1" }.Contains(val))
                        // 把 0 或者 1 转换为true 或false，以实现下面的转换
                        valStr = valStr == "0" ? "false" : "true";
                    if (!bool.TryParse(valStr, out var newVal)) throw new Exception("无效参数");
                    return Expression.Constant(newVal);
                default:
                    throw new NotImplementedException("未实现的类型");
            }

            throw new NotImplementedException("无效参数");
        }
    }
}
